package com.imooc.security.filter;

import com.imooc.security.entity.TokenInfo;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;

/**
 * @ClassName OAuthFilter
 * @Description TODO
 * @Author wushaopei
 * @Date 2021/5/3 17:49
 * @Version 1.0
 */
@Component
@Slf4j
public class OAuthFilter extends ZuulFilter {

    private RestTemplate restTemplate = new RestTemplate();
    /**
     * 过滤器类型：
     *  "pre"：在业务逻辑执行之前执行run()的逻辑
     *  "post"：在业务逻辑执行之后执行run()的逻辑
     *  "error"：在业务逻辑抛出异常执行run()的逻辑
     *  "route"：控制路由，一般不用这个，zuul已实现
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }
    //执行顺序
    @Override
    public int filterOrder() {
        return 1;
    }
    //是否过滤
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * @Description TODO 具体的业务逻辑 —— 认证逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        log.info("oauth start");

        // 获取请求头
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        if(StringUtils.startsWith(request.getRequestURI(),"/token")){
            return null;
        }
        // 获取请求头中的授权信息
        String authHeader = request.getHeader("Authorization");

        // auth是否为空
        if(StringUtils.isBlank(authHeader)){
            return null;
        }
        // 是否已获取到令牌
        if(!StringUtils.startsWithIgnoreCase(authHeader,"bearer")){
            return null;
        }

        try {
            TokenInfo info = getTokenInfo(authHeader);
            request.setAttribute("tokenInfo",info);
        }catch (Exception e){
            log.error("get token info fail", e);
        }
        return null;
    }

    /**
     * @Description TODO 用token到认证服务器验证是否为真
     * @param authHeader
     * @return
     */
    private TokenInfo getTokenInfo(String authHeader) {
        // 截取请求头里的bearer token
        String token = StringUtils.substringAfter(authHeader,"bearer ");
        // 认证服务器验token地址 /oauth/check_token 是  spring .security.oauth2的验token端点
        String oauthServiceUrl = "http://localhost:9090/oauth/check_token";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // 不是json请求
        // 网关的appId，appSecret，需要在数据库oauth_client_details注册
        headers.setBasicAuth("gateway","123456");
        // 封装token
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("token",token);

        HttpEntity<MultiValueMap<String,String>> entity = new HttpEntity<>(params,headers);
        ResponseEntity<TokenInfo> response = restTemplate.exchange(oauthServiceUrl, HttpMethod.POST,entity,TokenInfo.class);

        log.info("token info:" + response.getBody().toString());
        return response.getBody(); // 返回tokenInfo
    }
}
